#! /usr/bin/sdlbrt
'- from Paulo Silva, GPL license, june '10
'-   captures picture from a webcam (colour version), converts to ZX-Spectrum .scr (.tap), and sends the .tap sound to a ZX-Spectrum via mic cable
'- dependencies:
'-   sudo apt-get install fuse-emulator-utils sox imagemagick sdlbrt fswebcam
'-   sudo apt-get install xawtv vgrabbj pzxtools music123 lame mpg123 sdlbasic
'- needed:
'-   a linux computer with a working webcam (like using uvcvideo) and all needed packages installed
'-   a zx-spectrum running '10 load""screen$:go to 10', and connected by audio cable to a linux computer (like on a cassette player)
'-   sdlbasic for running this code
'- note:
'-   fuse-emulator-utils package is available from 

'------

xed=256:yed=192
setdisplay(xed,yed,32,1):paper(8^8-1):ink(0):pen(0):cls

captool$="fswebcam"

dim zxdisp[8192],zxtap[8192]
dim clust[8,8],r0[8,8],g0[8,8],b0[8,8],plte[16]

dim sphdr[32]:for i=0 to 31:sphdr[i]=0:next
sphdr[0]=19:sphdr[3]=3:sphdr[19]=128:sphdr[23]=255

while 0=0

  tapln=0
  specfinp$=left$("webcam_output",10)

  flsize=6912
  flsize2=flsize+2
  flsizeh=(int(flsize/256)) mod 256
  flsizel=flsize mod 256
  flsize2h=(int(flsize2/256)) mod 256
  flsize2l=flsize2 mod 256

  if captool$="vgrabbj" then
    setcaption("dummy")
    shell("vgrabbj -d /dev/video0 -F 4 -f _tmpr1.jpg")
    setcaption("del")
    shell("rm _tmpr1.jpg")
    setcaption("webcam")
    shell("vgrabbj -d /dev/video0 -F 4 -f _tmpr1.jpg")
    end if

  if captool$="fswebcam" then
    setcaption("del")
    shell("rm _tmpr1.jpg")
    setcaption("webcam")
    shell("fswebcam -d /dev/video0 _tmpr1.jpg")
    end if

  setcaption("imagemagick")

  shell("convert _tmpr1.jpg -resize 256x192\\! _tmpr2.jpg")
'  shell("convert _tmpr1.jpg -resize 256x192\\! -level 0,80%,1 _tmpr2.jpg")

  setcaption("del")
  shell("rm _tmpr1.jpg")
  setcaption("load")
  loadimage("_tmpr2.jpg",1):pasteicon(0,0,1)
  setcaption("del")
  shell("rm _tmpr2.jpg")
  setcaption("conv")


plte[ 0]=0x000000:plte[ 2]=0x0000B4:plte[ 1]=0xB40000:plte[ 3]=0xB400B4
plte[ 4]=0x00B400:plte[ 6]=0x00B4B4:plte[ 5]=0xB4B400:plte[ 7]=0xB4B4B4
plte[ 8]=0x000000:plte[10]=0x0000FF:plte[ 9]=0xFF0000:plte[11]=0xFF00FF
plte[12]=0x00FF00:plte[14]=0x00FFFF:plte[13]=0xFFFF00:plte[15]=0xFFFFFF
'- "00,12,03,15,08,04,11,07,02,14,01,13,10,06,09,05."
'- "00,06,08,14,02,12,04,10,08,14,00,06,04,10,02,12."
clstr$="00,06,08,14,02,12,04,10,08,14,00,06,04,10,02,12."
for y2=0 to 3:for x2=0 to 3:clust[x2,y2]=val(mid$(clstr$,((y2*4+x2)*3)+1,2)):next:next
hbedge=180 '- halfbright attr edge -zx32=218, zx32fs=153 , realthing=180?
rgrsp=30:ggrsp=30:bgrsp=30 '- for r, g and b saturation levels
for y1=0 to int(yed/8)-1:for x1=0 to int(xed/8)-1
    for y2=0 to 7:for x2=0 to 7
        y=y1*8+y2:x=x1*8+x2
        zzz=point(x,y)
        r0[x2,y2]=bitwiseand(zzz,255):zzz=int(zzz/256)
        g0[x2,y2]=bitwiseand(zzz,255):zzz=int(zzz/256)
        b0[x2,y2]=bitwiseand(zzz,255)
        next:next
    bi=0:ri=0:gi=0
    for y2=0 to 7:for x2=0 to 7
        x=(x1*8)+x2:y=(y1*8)+y2
        bi=bi+b0[x2,y2]:gi=gi+g0[x2,y2]:ri=ri+r0[x2,y2]
        next:next
    b=bi/64:g=gi/64:r=ri/64:xrreg=0
    hbrite=0:if (r<hbedge) and(g<hbedge) and(b<hbedge) then:hbrite=1:end if
    hbampl=255-(hbrite*(255-hbedge))
    if b>(hbampl/2) then:b=(hbampl-b):xrreg=bitwiseor(xrreg,1):end if
    if r>(hbampl/2) then:r=(hbampl-r):xrreg=bitwiseor(xrreg,2):end if
    if g>(hbampl/2) then:g=(hbampl-g):xrreg=bitwiseor(xrreg,4):end if
    halbr=(r*rgrsp)/100:halbg=(g*ggrsp)/100:halbb=(b*bgrsp)/100:vlik=7
    if((r>halbb) and(g<=halbb)) or((b<=halbr) and(g<=halbr))then:vlik=3:end if
    if((g>halbb) and(r<=halbb)) or((b<=halbg) and(r<=halbg))then:vlik=5:end if
    if((g>halbr) and(b<=halbr)) or((r<=halbg) and(b<=halbg))then:vlik=6:end if
    if((r<=halbb) and(g<=halbb)) then: vlik=1:end if
    if((b<=halbr) and(g<=halbr)) then: vlik=2:end if
    if((b<=halbg) and(r<=halbg)) then: vlik=4:end if
    brattr=1-hbrite
    ikattr=bitwisexor(vlik,xrreg)
    paattr=xrreg
    if ikattr<paattr then:
      tmpr=ikattr
      ikattr=paattr
      paattr=tmpr
      end if
    atvl=bitwiseor((ikattr*8),paattr)
    atvl=bitwiseor(atvl,(brattr*64))
    zxdisp[6144+x1+(y1*32)]=atvl
    ikval=ikattr+(bitwiseand(ikattr,6)/2)
    paval=paattr+(bitwiseand(paattr,6)/2)
    lumik=(ikval*255)/10:lumpa=(paval*255)/10
    if brattr<1 then:lumik=(lumik*hbedge)/255:lumpa=(lumpa*hbedge)/255:end if 
    dflum=lumik-lumpa
    for y2=0 to 7
      dbny=0
      for x2=0 to 7
        y=y1*8+y2
        x=x1*8+x2
        b=b0[x2,y2]
        g=g0[x2,y2]
        r=r0[x2,y2]
        vlue=((b+(r*3)+(g*6))/10)
        patgf=(((clust[bitwiseand(x2,3),bitwiseand(y2,3)]+1)*255)/16)
        varnd=((patgf*dflum)/255)+lumpa
        ik=ikattr+(8*brattr)
        if varnd>vlue then:
          ik=paattr+(8*brattr)
          dbny=dbny+(2^(7-x2))
          end if
        ink(plte[ik]):dot(x,y)
        next
      yf=bitwiseor((bitwiseand(y,7)*8),(bitwiseand(y,56)/8))
      yf=bitwiseor(yf,bitwiseand(y,192))
      zxdisp[(yf*32)+x1]=dbny
      next:next:next


setcaption("saving .scr and .tap")

open "__tmpscr.scr" for output as #1
for i=0 to 6911
  writebyte(1,zxdisp[i])
  next
close #1

for i=0 to 9
  u=asc(mid$(specfinp$,i+1,1))
  zxtap[tapln+i+4]=u
  next

zxtap[tapln+14]=flsizel:zxtap[tapln+15]=flsizeh
zxtap[tapln+21]=flsize2l:zxtap[tapln+22]=flsize2h

checksum=0
for i=2 to 19
  checksum=bitwisexor(checksum,zxtap[tapln+i])
  next

zxtap[tapln+20]=checksum

checksum=255
for i=0 to flsize-1
  zxtap[tapln+i+24]=zxdisp[i]
  checksum=bitwisexor(checksum,zxdisp[i])
  next
zxtap[tapln+flsize+24]=checksum
tapln=tapln+(flsize+25)

zxtap[0]=19:zxtap[3]=3:zxtap[19]=128:zxtap[23]=255

open "_tmp_.tap" for output as #2
for i=0 to tapln-1
  writebyte(2,zxtap[i])
  next
close #2

setcaption(".tap log...")
shell("cat _tmp_.tap >> _whole_.tap")

setcaption("tape2wav...")
shell("tape2wav _tmp_.tap _tmp_.wav")

setcaption("sox play...")
shell("play _tmp_.wav")

'waitkey
wend
